/**
 * 进程查找模块
 * 用于查找运行中的桌面应用进程
 */

const os = require('os');
const path = require('path');
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);

// 桌面应用关键词（用于过滤和识别桌面应用）
const DESKTOP_APP_KEYWORDS = ['Electron', 'Chrome', 'Firefox', 'Edge', 'Safari', 'Opera', 
  'Visual Studio', '.NET', 'AppData', 'Qt', 'WPF', 'Microsoft', 'Unity', 'MacOS', 
  'WindowsCE', 'Frameworks', 'Library/Application Support', 'AppContainer', 'C++'];

// 浏览器进程（用于排除）
const BROWSER_PROCESSES = ['chrome', 'firefox', 'msedge', 'safari', 'opera', 'iexplore', 'brave'];

/**
 * 查找运行中的桌面应用进程
 * @returns {Promise<Array<Object>>} 进程信息数组
 */
async function findDesktopProcesses() {
  const platform = os.platform();
  let processes = [];

  try {
    if (platform === 'win32') {
      processes = await findWindowsProcesses();
    } else if (platform === 'darwin') {
      processes = await findMacOSProcesses();
    } else if (platform === 'linux') {
      processes = await findLinuxProcesses();
    }

    // 过滤并丰富进程信息
    const enrichedProcesses = [];
    for (const proc of processes) {
      // 跳过系统进程和浏览器进程
      if (isSystemProcess(proc.name) || isBrowserProcess(proc.name)) {
        continue;
      }

      // 检查是否为桌面应用
      if (isDesktopApplication(proc.cmd || proc.name)) {
        // 查找用户数据目录
        const userDataDir = await findUserDataDir(proc.name, proc.pid, platform);
        
        enrichedProcesses.push({
          pid: proc.pid,
          name: proc.name,
          cmd: proc.cmd || '',
          userDataDir
        });
      }
    }

    return enrichedProcesses;
  } catch (err) {
    console.error(`查找桌面应用进程出错: ${err.message}`);
    return [];
  }
}

/**
 * 查找Windows系统的进程
 * @returns {Promise<Array<Object>>} 进程信息数组
 */
async function findWindowsProcesses() {
  try {
    // 使用wmic获取进程信息
    const { stdout } = await execAsync('wmic process get ProcessID,Name,CommandLine /format:csv');
    
    // 解析CSV输出
    const lines = stdout.trim().split('\n');
    const processes = [];
    
    for (let i = 1; i < lines.length; i++) {
      const line = lines[i].trim();
      if (!line) continue;
      
      const parts = line.split(',');
      if (parts.length >= 3) {
        const name = parts[parts.length - 2];
        const pid = parseInt(parts[parts.length - 1], 10);
        const cmd = parts.slice(1, parts.length - 2).join(',');
        
        processes.push({ pid, name, cmd });
      }
    }
    
    return processes;
  } catch (err) {
    console.error(`查找Windows进程出错: ${err.message}`);
    return [];
  }
}

/**
 * 查找macOS系统的进程
 * @returns {Promise<Array<Object>>} 进程信息数组
 */
async function findMacOSProcesses() {
  try {
    // 使用ps命令获取进程信息
    const { stdout } = await execAsync('ps -eo pid,command');
    
    const lines = stdout.trim().split('\n');
    const processes = [];
    
    for (let i = 1; i < lines.length; i++) {
      const line = lines[i].trim();
      if (!line) continue;
      
      const match = line.match(/^\s*(\d+)\s+(.+)$/);
      if (match) {
        const pid = parseInt(match[1], 10);
        const cmd = match[2];
        
        // 提取应用名称
        let name = '';
        
        if (cmd.includes('.app/Contents/MacOS/')) {
          // macOS应用格式：/Applications/App.app/Contents/MacOS/executable
          const appMatch = cmd.match(/\/([^\/]+)\.app\/Contents\/MacOS\/([^\/\s]+)/);
          if (appMatch) {
            name = appMatch[1];
          } else {
            name = path.basename(cmd);
          }
        } else {
          name = path.basename(cmd.split(' ')[0]);
        }
        
        processes.push({ pid, name, cmd });
      }
    }
    
    return processes;
  } catch (err) {
    console.error(`查找macOS进程出错: ${err.message}`);
    return [];
  }
}

/**
 * 查找Linux系统的进程
 * @returns {Promise<Array<Object>>} 进程信息数组
 */
async function findLinuxProcesses() {
  try {
    // 使用ps命令获取进程信息
    const { stdout } = await execAsync('ps -eo pid,cmd');
    
    const lines = stdout.trim().split('\n');
    const processes = [];
    
    for (let i = 1; i < lines.length; i++) {
      const line = lines[i].trim();
      if (!line) continue;
      
      const match = line.match(/^\s*(\d+)\s+(.+)$/);
      if (match) {
        const pid = parseInt(match[1], 10);
        const cmd = match[2];
        const name = path.basename(cmd.split(' ')[0]);
        
        processes.push({ pid, name, cmd });
      }
    }
    
    return processes;
  } catch (err) {
    console.error(`查找Linux进程出错: ${err.message}`);
    return [];
  }
}

/**
 * 判断进程是否为系统进程
 * @param {string} processName - 进程名称
 * @returns {boolean} 是否为系统进程
 */
function isSystemProcess(processName) {
  const systemProcesses = [
    'svchost', 'explorer', 'system', 'smss', 'wininit', 'csrss', 'services', 
    'lsass', 'fontdrvhost', 'registry', 'logonui', 'dwm', 'ctfmon',
    'launchd', 'kernel_task', 'WindowServer', 'mds', 'mdworker', 'distnoted',
    'systemd', 'init', 'kthreadd', 'kworker', 'dbus-daemon'
  ];
  
  return systemProcesses.some(sysProc => 
    processName.toLowerCase().includes(sysProc.toLowerCase()));
}

/**
 * 判断进程是否为浏览器进程
 * @param {string} processName - 进程名称
 * @returns {boolean} 是否为浏览器进程
 */
function isBrowserProcess(processName) {
  return BROWSER_PROCESSES.some(browser => 
    processName.toLowerCase().includes(browser.toLowerCase()));
}

/**
 * 判断进程是否为桌面应用
 * @param {string} cmdLine - 进程命令行
 * @returns {boolean} 是否为桌面应用
 */
function isDesktopApplication(cmdLine) {
  if (!cmdLine) return false;
  
  // 检查命令行是否包含桌面应用关键词
  const containsKeyword = DESKTOP_APP_KEYWORDS.some(keyword => 
    cmdLine.includes(keyword));
  
  // 检查是否为Electron应用
  const isElectron = cmdLine.includes('--type=renderer') || 
                    cmdLine.includes('--app=') || 
                    cmdLine.includes('electron');
  
  // 检查是否为.NET应用
  const isDotNet = cmdLine.includes('.NET') || 
                  cmdLine.includes('.exe') && (
                    cmdLine.includes('Framework') || 
                    cmdLine.includes('v4.0') ||
                    cmdLine.includes('AppData')
                  );
  
  // 检查是否为macOS应用
  const isMacApp = cmdLine.includes('.app/Contents/MacOS/');
  
  // 检查是否为Qt应用
  const isQtApp = cmdLine.includes('Qt') || cmdLine.includes('QtWebEngine');
  
  return containsKeyword || isElectron || isDotNet || isMacApp || isQtApp;
}

/**
 * 查找进程的用户数据目录
 * @param {string} procName - 进程名称
 * @param {number} pid - 进程ID
 * @param {string} platform - 操作系统平台
 * @returns {Promise<string>} 用户数据目录
 */
async function findUserDataDir(procName, pid, platform) {
  // 清理进程名
  const appName = procName.replace(/\.(exe|app)$/i, '');
  
  try {
    if (platform === 'win32') {
      return await findWindowsUserDataDir(appName, pid);
    } else if (platform === 'darwin') {
      return await findMacOSUserDataDir(appName, pid);
    } else {
      return await findLinuxUserDataDir(appName, pid);
    }
  } catch (err) {
    console.error(`查找用户数据目录出错: ${err.message}`);
    return '';
  }
}

/**
 * 查找Windows应用的用户数据目录
 * @param {string} appName - 应用名称
 * @param {number} pid - 进程ID
 * @returns {Promise<string>} 用户数据目录
 */
async function findWindowsUserDataDir(appName, pid) {
  // Windows常见用户数据目录位置
  const appData = process.env.APPDATA || `${process.env.USERPROFILE}\\AppData\\Roaming`;
  const localAppData = process.env.LOCALAPPDATA || `${process.env.USERPROFILE}\\AppData\\Local`;
  
  // 尝试查找进程的模块路径
  try {
    const { stdout } = await execAsync(`wmic process where processid=${pid} get ExecutablePath`);
    const exePath = stdout.trim().split('\n')[1] || '';
    
    if (exePath) {
      const exeDir = path.dirname(exePath);
      
      // 检查可能的用户数据目录
      const possibleDirs = [
        // Electron应用常见位置
        path.join(exeDir, 'resources', 'app.asar'),
        path.join(exeDir, 'resources', 'app'),
        path.join(appData, appName),
        path.join(localAppData, appName),
        // .NET/C#应用常见位置
        path.join(localAppData, `${appName}_StrongName`),
        path.join(appData, `${appName}_StrongName`),
        path.join(appData, appName, 'user.config'),
        // C++应用常见位置
        path.join(localAppData, appName),
        path.join(localAppData, 'Temp', appName),
        path.join(process.env.USERPROFILE || '', 'Documents', appName)
      ];
      
      for (const dir of possibleDirs) {
        try {
          if (require('fs').existsSync(dir)) {
            return dir;
          }
        } catch (e) {
          // 忽略访问错误
        }
      }
      
      // 如果找不到特定目录，返回可执行文件所在目录
      return exeDir;
    }
  } catch (err) {
    console.error(`查找Windows用户数据目录出错: ${err.message}`);
  }
  
  // 默认位置
  return path.join(appData, appName);
}

/**
 * 查找macOS应用的用户数据目录
 * @param {string} appName - 应用名称
 * @param {number} pid - 进程ID
 * @returns {Promise<string>} 用户数据目录
 */
async function findMacOSUserDataDir(appName, pid) {
  const home = process.env.HOME || `/Users/${process.env.USER}`;
  
  // 尝试查找进程的工作目录
  try {
    const { stdout } = await execAsync(`lsof -p ${pid} | grep cwd`);
    const cwdMatch = stdout.match(/\s+(\/.*?)\s+/);
    
    if (cwdMatch && cwdMatch[1]) {
      return cwdMatch[1];
    }
  } catch (err) {
    // 忽略lsof错误
  }
  
  // 尝试常见的macOS应用数据目录
  const possibleDirs = [
    // Electron应用常见位置
    path.join(home, 'Library', 'Application Support', appName),
    // macOS原生应用常见位置
    path.join(home, 'Library', 'Containers', `${appName}`),
    path.join(home, 'Library', 'Containers', `com.${appName.toLowerCase()}`),
    path.join(home, 'Library', 'Containers', `com.${appName.toLowerCase()}`, 'Data', 'Library'),
    // C++应用常见位置
    path.join(home, 'Library', 'Preferences', `${appName}`),
    path.join(home, 'Library', 'Preferences', `com.${appName.toLowerCase()}`),
    path.join(home, 'Library', 'Caches', appName),
    path.join(home, 'Library', 'Group Containers', `${appName.toLowerCase()}.group`)
  ];
  
  for (const dir of possibleDirs) {
    try {
      if (require('fs').existsSync(dir)) {
        return dir;
      }
    } catch (e) {
      // 忽略访问错误
    }
  }
  
  // 默认位置
  return path.join(home, 'Library', 'Application Support', appName);
}

/**
 * 查找Linux应用的用户数据目录
 * @param {string} appName - 应用名称
 * @param {number} pid - 进程ID
 * @returns {Promise<string>} 用户数据目录
 */
async function findLinuxUserDataDir(appName, pid) {
  const home = process.env.HOME || `/home/${process.env.USER}`;
  
  // 尝试查找进程的工作目录
  try {
    const { stdout } = await execAsync(`readlink /proc/${pid}/cwd`);
    if (stdout.trim()) {
      return stdout.trim();
    }
  } catch (err) {
    // 忽略readlink错误
  }
  
  // 尝试常见的Linux应用数据目录
  const possibleDirs = [
    // Electron应用常见位置
    path.join(home, '.config', appName),
    // 桌面应用常见位置
    path.join(home, '.local', 'share', appName),
    path.join(home, '.cache', appName),
    // Qt应用常见位置
    path.join(home, '.config', 'QtProject'),
    // C++应用常见位置
    path.join(home, '.local', 'share', appName.toLowerCase()),
    path.join(home, '.cache', appName.toLowerCase())
  ];
  
  for (const dir of possibleDirs) {
    try {
      if (require('fs').existsSync(dir)) {
        return dir;
      }
    } catch (e) {
      // 忽略访问错误
    }
  }
  
  // 默认位置
  return path.join(home, '.config', appName);
}

/**
 * 获取进程详细信息
 * @param {number} pid - 进程ID
 * @returns {Promise<Object>} 进程详细信息
 */
async function getProcessDetail(pid) {
  const platform = os.platform();
  
  try {
    if (platform === 'win32') {
      const { stdout } = await execAsync(`wmic process where processid=${pid} get ExecutablePath,CommandLine /format:list`);
      const lines = stdout.trim().split('\n');
      const detail = {};
      
      for (const line of lines) {
        const parts = line.split('=');
        if (parts.length === 2) {
          const key = parts[0].trim();
          const value = parts[1].trim();
          detail[key] = value;
        }
      }
      
      return {
        pid,
        path: detail.ExecutablePath || '',
        cmd: detail.CommandLine || ''
      };
    } else if (platform === 'darwin') {
      const { stdout } = await execAsync(`ps -p ${pid} -o command`);
      const cmd = stdout.trim().split('\n')[1] || '';
      
      return {
        pid,
        path: cmd.split(' ')[0],
        cmd
      };
    } else { // Linux
      const { stdout } = await execAsync(`ps -p ${pid} -o cmd`);
      const cmd = stdout.trim().split('\n')[1] || '';
      
      // 尝试读取/proc/pid/exe获取实际路径
      try {
        const { stdout: exePath } = await execAsync(`readlink /proc/${pid}/exe`);
        return {
          pid,
          path: exePath.trim(),
          cmd
        };
      } catch (err) {
        return {
          pid,
          path: cmd.split(' ')[0],
          cmd
        };
      }
    }
  } catch (err) {
    console.error(`获取进程详情出错: ${err.message}`);
    return { pid, path: '', cmd: '' };
  }
}

module.exports = {
  findDesktopProcesses,
  getProcessDetail,
  findUserDataDir
}; 